<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
</head>
<body>

  <dom-module id='test-static'>
    <template>
      <div>static</div>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-static'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content'>
    <template>
      <span id="contentContainer">[<content id="content"></content>]</span>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content1'>
    <template>
      <test-content id="content"><content></content></test-content>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content1'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content2'>
    <template>
      <test-content1 id="content"><content></content></test-content1>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content2'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content3'>
    <template>
      <test-content2 id="content"><content></content></test-content2>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content3'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-raw'>
    <template>
      <div id="content"><content></content></div>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-raw'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-attr'>
    <template>
      [<content id="content" select="[d]"></content>]
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-attr'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-attr1'>
    <template>
      <test-content-attr id="content"><content select="[c]"></content></test-content-attr>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-attr1'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-attr2'>
    <template>
      <test-content-attr1 id="content"><content select="[b]"></content></test-content-attr1>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-attr2'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-attr3'>
    <template>
      <test-content-attr2 id="content"><content select="[a]"></content></test-content-attr2>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-attr3'
      });
    });
    </script>
  </dom-module>

  <dom-module id='test-content-attr-inside'>
    <template>
      <test-content-attr3 id="content"><content></content></test-content-attr3>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is:'test-content-attr-inside'
      });
    });
    </script>
  </dom-module>


  <test-content><div>A</div><div>B</div></test-content>

  <test-static><div>static A</div><div>static B</div></test-static>

  <div id="staticDiv"></div>

<script>

  suite('observeNodes', function() {

    test('observe intial state of distributing element', function() {
      var recordedA;
      var el = document.querySelector('test-content');
      Polymer.dom(el).observeNodes(function(info) {
        recordedA = info;
      });
      Polymer.dom.flush();
      assert.equal(recordedA.addedNodes.length, 2);
      recordedA = null;
      var recordedB;
      Polymer.dom(el).observeNodes(function(info) {
        recordedB = info;
      });
      Polymer.dom.flush();
      assert.equal(recordedA, null);
      assert.equal(recordedB.addedNodes.length, 2);
    });

    test('observe intial state of non-distributing element', function() {
      var recordedA;
      var el = document.querySelector('test-static');
      Polymer.dom(el).observeNodes(function(info) {
        recordedA = info;
      });
      Polymer.dom.flush();
      assert.equal(recordedA.addedNodes.length, 2);
      recordedA = null;
      var recordedB;
      Polymer.dom(el).observeNodes(function(info) {
        recordedB = info;
      });
      Polymer.dom.flush();
      assert.equal(recordedA, null);
      assert.equal(recordedB.addedNodes.length, 2);
    });

    test('observe children changes to distributing element', function() {
      var el = document.createElement('test-content');
      document.body.appendChild(el);

      var recorded;
      var handle = Polymer.dom(el).observeNodes(function(info) {
        recorded = info;
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // reset, unobserve and remove
      recorded = null;
      Polymer.dom(el).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      document.body.removeChild(el);
    });

    test('observe children changes to distributing element that provoke additional changes', function() {
      var el = document.createElement('test-content');
      document.body.appendChild(el);

      var recordedInfo, elAddedInObserver;
      var observerCallCount = 0;
      Polymer.dom(el).observeNodes(function(info) {
        if (Polymer.dom(info.target).childNodes.length < 5) {
          elAddedInObserver = document.createElement('div');
          Polymer.dom(info.target).appendChild(elAddedInObserver);
        }
        observerCallCount++;
        recordedInfo = info;
      });
      // add
      var d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(observerCallCount, 5);
      assert.equal(recordedInfo.addedNodes.length, 1);
      assert.equal(recordedInfo.addedNodes[0], elAddedInObserver);
      assert.equal(Polymer.dom(el).childNodes.length, 5);
      document.body.removeChild(el);
    });

    test('observe children changes to distributing element (async)', function(done) {
      var el = document.createElement('test-content');
      document.body.appendChild(el);

      var nodes = [];
      var handle = Polymer.dom(el).observeNodes(function(info) {
        for (var i=0, at; i < info.removedNodes.length; i++) {
          at = nodes.indexOf(info.removedNodes[i]);
          assert.isAbove(at, -1);
          nodes.splice(at, 1);
        }
        nodes = nodes.concat(info.addedNodes);
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      setTimeout(function() {
        assert.sameMembers(el.getEffectiveChildNodes(), nodes);
        // remove
        Polymer.dom(el).removeChild(d);
        Polymer.dom(el).removeChild(d1);
        setTimeout(function() {
          assert.sameMembers(el.getEffectiveChildNodes(), nodes);
          // add
          Polymer.dom(el).appendChild(d);
          Polymer.dom(el).appendChild(d1);
          setTimeout(function() {
            assert.sameMembers(el.getEffectiveChildNodes(), nodes);
            Polymer.dom(el).unobserveNodes(handle);
            Polymer.dom(el).removeChild(d);
            Polymer.dom(el).removeChild(d1);
            setTimeout(function() {
              assert.notEqual(nodes.length, el.getEffectiveChildNodes().length);
              document.body.removeChild(el);
              done();
            });
          });
        });
      });
    });

    test('observe children changes to non-distributing element', function() {
      var el = document.createElement('test-static');
      document.body.appendChild(el);

      var recorded;
      var handle = Polymer.dom(el).observeNodes(function(info) {
        recorded = info;
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // reset, unobserve and remove
      recorded = null;
      Polymer.dom(el).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      document.body.removeChild(el);
    });

    test('observe changes to inner node wrapping <content>', function() {
      var el = document.createElement('test-content');
      document.body.appendChild(el);
      var observedInfo;
      var handle = Polymer.dom(el.$.contentContainer).observeNodes(function(info) {
        observedInfo = info;
      });
      Polymer.dom.flush();
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.target, el.$.contentContainer);
      assert.equal(observedInfo.addedNodes.length, 2);
      assert.equal(observedInfo.removedNodes.length, 0);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.addedNodes.length, 0);
      assert.equal(observedInfo.removedNodes.length, 2);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.addedNodes.length, 2);
      assert.equal(observedInfo.removedNodes.length, 0);
      // reset, unobserve and remove
      observedInfo = null;
      Polymer.dom(el.$.contentContainer).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo, null);
      document.body.removeChild(el);
    });

    test('observe changes to <content>', function() {
      var el = document.createElement('test-content');
      document.body.appendChild(el);
      var observedInfo;
      var handle = Polymer.dom(el.$.content).observeNodes(function(info) {
        observedInfo = info;
      });
      Polymer.dom.flush();
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.target, el.$.content);
      assert.equal(observedInfo.addedNodes.length, 2);
      assert.equal(observedInfo.removedNodes.length, 0);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.addedNodes.length, 0);
      assert.equal(observedInfo.removedNodes.length, 2);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo.addedNodes.length, 2);
      assert.equal(observedInfo.removedNodes.length, 0);
      // reset, unobserve and remove
      observedInfo = null;
      Polymer.dom(el.$.content).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(observedInfo, null);
      document.body.removeChild(el);
    });

    test('observe effective children inside distributing element', function() {
      var el = document.createElement('test-content1');
      document.body.appendChild(el);
      var recorded;
      var handle = Polymer.dom(el.$.content).observeNodes(function(info) {
        recorded = info;
      });
      Polymer.dom.flush();
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // reset, unobserve and remove
      recorded = null;
      Polymer.dom(el.$.content).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      document.body.removeChild(el);
    });

    test('observe effective children changes when adding to another host', function() {
      var el = document.createElement('test-content1');
      document.body.appendChild(el);
      var recorded;
      Polymer.dom(el.$.content).observeNodes(function(info) {
        recorded = info;
      });
      Polymer.dom.flush();
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // add somewhere else... we should see these as removes
      Polymer.dom(document.body).appendChild(d);
      Polymer.dom(document.body).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // cleanup
      Polymer.dom(document.body).removeChild(d);
      Polymer.dom(document.body).removeChild(d1);
      document.body.removeChild(el);
    });

    test('observe effective children changes in static content when adding to another host', function() {
      var el = document.createElement('staticDiv');
      document.body.appendChild(el);
      var recorded;
      Polymer.dom(el).observeNodes(function(info) {
        recorded = info;
      });
      Polymer.dom.flush();
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // add somewhere else... we should see these as removes
      Polymer.dom(document.body).appendChild(d);
      Polymer.dom(document.body).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // cleanup
      Polymer.dom(document.body).removeChild(d);
      Polymer.dom(document.body).removeChild(d1);
      document.body.removeChild(el);
    });

    test('observe effective children inside deep distributing element', function() {
      var el = document.createElement('test-content3');
      document.body.appendChild(el);

      var recorded;
      var content = el.$.content.$.content.$.content;
      var handle = Polymer.dom(content).observeNodes(function(info) {
        recorded = info;
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // reset, unobserve and remove
      recorded = null;
      Polymer.dom(content).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      document.body.removeChild(el);
    });

    test('observe <content> inside deep distributing element', function() {
      var el = document.createElement('test-content3');
      document.body.appendChild(el);

      var recorded;
      var content = el.$.content.$.content.$.content.$.content;
      assert.equal(content.localName, 'content');
      var handle = Polymer.dom(content).observeNodes(function(info) {
        recorded = info;
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.removedNodes.length, 0);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // remove
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 0);
      assert.equal(recorded.removedNodes.length, 2);
      assert.equal(recorded.removedNodes[0], d);
      assert.equal(recorded.removedNodes[1], d1);
      // add
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded.addedNodes.length, 2);
      assert.equal(recorded.addedNodes[0], d);
      assert.equal(recorded.addedNodes[1], d1);
      // reset, unobserve and remove
      recorded = null;
      Polymer.dom(content).unobserveNodes(handle);
      Polymer.dom(el).removeChild(d);
      Polymer.dom(el).removeChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      document.body.removeChild(el);
    });

    test('observe effective children inside deep distributing element (async)', function(done) {
      var el = document.createElement('test-content3');
      document.body.appendChild(el);

      var recorded;
      var content = el.$.content.$.content.$.content;
      var handle = Polymer.dom(content).observeNodes(function(info) {
        recorded = info;
      });
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      setTimeout(function() {
        assert.equal(recorded.addedNodes.length, 2);
        assert.equal(recorded.removedNodes.length, 0);
        assert.equal(recorded.addedNodes[0], d);
        assert.equal(recorded.addedNodes[1], d1);
        // remove
        Polymer.dom(el).removeChild(d);
        Polymer.dom(el).removeChild(d1);
        setTimeout(function() {
          assert.equal(recorded.addedNodes.length, 0);
          assert.equal(recorded.removedNodes.length, 2);
          assert.equal(recorded.removedNodes[0], d);
          assert.equal(recorded.removedNodes[1], d1);
          // add
          Polymer.dom(el).appendChild(d);
          Polymer.dom(el).appendChild(d1);
          setTimeout(function() {
            assert.equal(recorded.addedNodes.length, 2);
            assert.equal(recorded.addedNodes[0], d);
            assert.equal(recorded.addedNodes[1], d1);
            // reset, unobserve and remove
            recorded = null;
            Polymer.dom(content).unobserveNodes(handle);
            Polymer.dom(el).removeChild(d);
            Polymer.dom(el).removeChild(d1);
            setTimeout(function() {
              assert.equal(recorded, null);
              document.body.removeChild(el);
              done();
            });
          });
        });
      });
    });


    test('observe effective children attr changes inside deep distributing element (async)', function(done) {
      var el = document.createElement('test-content-attr3');
      document.body.appendChild(el);

      var recorded;
      var content = el.$.content.$.content.$.content;
      var handle = Polymer.dom(content).observeNodes(function(info) {
        recorded = info;
      }, {attributes: true});
      Polymer.dom.flush();
      recorded = null;
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      Polymer.dom(d).setAttribute('a', '');
      Polymer.dom(d).setAttribute('b', '');
      setTimeout(function() {
        assert.equal(recorded, null);
        Polymer.dom(d).setAttribute('c', '');
        setTimeout(function() {
          assert.equal(recorded.addedNodes.length, 1);
          assert.equal(recorded.removedNodes.length, 0);
          assert.equal(recorded.addedNodes[0], d);
          Polymer.dom(d).removeAttribute('c');
          setTimeout(function() {
            assert.equal(recorded.addedNodes.length, 0);
            assert.equal(recorded.removedNodes.length, 1);
            assert.equal(recorded.removedNodes[0], d);
            recorded = null;
            Polymer.dom(content).unobserveNodes(handle);
            Polymer.dom(d).setAttribute('c', '');
            setTimeout(function() {
              assert.equal(recorded, null);
              document.body.removeChild(el);
              done();
            });
          });
        });
      });
    });

    test('observe effective children attr changes inside deep distributing element without outer select (async)', function(done) {
      var el = document.createElement('test-content-attr-inside');
      document.body.appendChild(el);

      var recorded;
      var content = el.$.content.$.content.$.content.$.content;
      var handle = Polymer.dom(content).observeNodes(function(info) {
        recorded = info;
      }, {attributes: true});
      Polymer.dom.flush();
      recorded = null;
      // add
      var d = document.createElement('div');
      var d1 = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom(el).appendChild(d1);
      Polymer.dom.flush();
      assert.equal(recorded, null);
      Polymer.dom(d).setAttribute('a', '');
      Polymer.dom(d).setAttribute('b', '');
      setTimeout(function() {
        assert.equal(recorded, null);
        Polymer.dom(d).setAttribute('c', '');
        setTimeout(function() {
          assert.equal(recorded.addedNodes.length, 1);
          assert.equal(recorded.removedNodes.length, 0);
          assert.equal(recorded.addedNodes[0], d);
          Polymer.dom(d).removeAttribute('c');
          setTimeout(function() {
            assert.equal(recorded.addedNodes.length, 0);
            assert.equal(recorded.removedNodes.length, 1);
            assert.equal(recorded.removedNodes[0], d);
            recorded = null;
            Polymer.dom(content).unobserveNodes(handle);
            Polymer.dom(d).setAttribute('c', '');
            setTimeout(function() {
              assert.equal(recorded, null);
              document.body.removeChild(el);
              done();
            });
          });
        });
      });
    });

    test('add/remove multiple observers', function() {
      var el = document.createElement('test-content1');
      document.body.appendChild(el);
      var r1 = 0;
      var h1 = Polymer.dom(el.$.content).observeNodes(function() {
        r1++;
      });
      var r2 = 0;
      var h2 = Polymer.dom(el.$.content).observeNodes(function() {
        r2++;
      });
      var r3 = 0;
      var h3 = Polymer.dom(el.$.content).observeNodes(function() {
        r3++;
      });
      // add
      var d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 1);
      assert.equal(r2, 1);
      assert.equal(r3, 1);
      Polymer.dom(el.$.content).unobserveNodes(h1);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 1);
      assert.equal(r2, 2);
      assert.equal(r3, 2);
      Polymer.dom(el.$.content).unobserveNodes(h2);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 1);
      assert.equal(r2, 2);
      assert.equal(r3, 3);
      Polymer.dom(el.$.content).unobserveNodes(h3);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 1);
      assert.equal(r2, 2);
      assert.equal(r3, 3);
      h1 = Polymer.dom(el.$.content).observeNodes(h1.fn);
      h2 = Polymer.dom(el.$.content).observeNodes(h2.fn);
      h3 = Polymer.dom(el.$.content).observeNodes(h3.fn);
      Polymer.dom.flush();
      assert.equal(r1, 2);
      assert.equal(r2, 3);
      assert.equal(r3, 4);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 3);
      assert.equal(r2, 4);
      assert.equal(r3, 5);
      Polymer.dom(el.$.content).unobserveNodes(h3);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 4);
      assert.equal(r2, 5);
      assert.equal(r3, 5);
      Polymer.dom(el.$.content).unobserveNodes(h2);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 5);
      assert.equal(r2, 5);
      assert.equal(r3, 5);
      Polymer.dom(el.$.content).unobserveNodes(h1);
      d = document.createElement('div');
      Polymer.dom(el).appendChild(d);
      Polymer.dom.flush();
      assert.equal(r1, 5);
      assert.equal(r2, 5);
      assert.equal(r3, 5);
    });

  });

</script>

</body>
</html>
